/**
 *  @file .
 *  @author wangxiaowei <wangxiaowei0303@163.com>
 *  @date 2015-02-26-09.59
 *  CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
 */

/**
 *  本次参考的源码版本;
 *    1. 宏 _GLIBCXX_USE_CXX11_ABI 未启用.
 *
 *  NOTE,本次源码学习略过以下细节;
 *    1. char_traits
 *    2. 原子性.以及线程安全
 *    3. 将所有 Alloc 都视为 allocator,
 *
 *  _M_ 前缀;表明函数成员,数据成员是非静态的.
 *  _S_ 前缀;表明函数成员,数据成员是静态的.
 *
 *  std::string 的结构:
 *   _M_dataplus._M_p
 *                 ↓
 *     +------------------------------------------------+
 *     |    _Rep   |             string data            |
 *     +------------------------------------------------+
 *  LD. 采用了隐式共享,写时复制的技术;
 */

#ifndef org_wxw_stl_study_include_bits_basic_string_h_
#define org_wxw_stl_study_include_bits_basic_string_h_

#include "cpp_type_traits.h"

namespace std{

template<typename CharT,typename Traits,typename Alloc>
class basic_string{
private: // 类型成员

    typedef typename Alloc::template rebind<CharT>::other _CharT_alloc_type;
    // 等同于 typedef allocator<CharT> _CharT_alloc_type,即 _CharT_alloc_type
    // 用于给 CharT 类型的对象分配内存.

public: // 类型成员
    typedef typename _CharT_alloc_type::size_type size_type;
    // allocator_type,就是当前字符串中,内存分配器的类型.
    typedef Alloc allocator_type;

private: // 类型成员

    /**
     *  _M_length;表明字符串对象中当前字符个数.
     *  _M_capacity; 表明当前字符串对象最多可以存放的字符个数
     *  _M_refcount; 引用计数.
     *    -1;leaked;一个引用,不可共享
     *    0;一个引用;可被共享
     *    n;n+1 个引用.
     *  LD. 在当前实现中,字符串对象总会追加空字符('\0').
     */
    struct _Rep_base{
        size_type _M_length;
        size_type _M_capacity;
        _Atomic_word _M_refcount;
    }; // struct _Rep_base;

    struct _Rep: public _Rep_base{
        // 等同于 typedef allocator<char> _Raw_bytes_alloc
        typedef typename Alloc::template rebind<char>::other _Raw_bytes_alloc;

        /**
         *  实现的字符串所能容纳的最大字符个数.
         *  basic_string::npos;内存分配器所能分配的最大字节数.
         *  则有关系式:
         *  sizeof(_Rep)+(_S_max_size+1)*sizeof(CharT) == npos;即:
         *  _S_max_size = (npos-sizeof(_Rep))/sizeof(CharT)-1;
         */
        static const size_type _S_max_size;

        /// 字符串使用的终止字符
        static const CharT _S_terminal;

        /**
         *  空串;参见上对 std::string 结构的分析,若需要构建一个空串,则我们
         *  的做法可以是:
         *    void *place = malloc(sizeof(_Rep)+sizeof(CharT))
         *    memset(place,0,sizeof(_Rep)+sizeof(CharT));
         *    _M_dataplus._M_p = (char*)place+sizeof(_Rep);
         *  即为空串也动态分配内存.
         *  而在 libstdc++ 中,当构建一个空串时,并不动态分配内存,而是事先
         *  在全局作用域中静态分配一个空串,然后直接
         *    _M_dataplus._M_p = (char*)_S_empty_rep_storage+sizeof(_Rep);
         *  LD.空串
         */
        static size_type _S_empty_rep_storage[];

        /// 获取在全局作用域静态分配的空串中 _Rep 对象的引用.
        static _Rep&
        _S_empty_rep(){
            return *((_Rep*)_S_empty_rep_storage);
        }

        /// 测试当前字符串对象是否是 leaked 的
        bool
        _M_is_leaked()const;

        /// 测试当前字符串对象是否是共享着的,即 _M_refcount>0.
        bool
        _M_is_shared()const;

        /// 将当前字符串设置为 leaked,即不可共享.
        void
        _M_set_leaked();

        /// 将当前字符串设置为 sharable,即可共享的(refcount==0)
        void
        _M_set_sharable();

        /**
         *  将当前字符串的长度设置为 l,并追加空字符;然后设置为 sharable.
         *  若当前字符串是空串(并且 FULLY_DYNAMIC_STRING==0),则直接返回.
         */
        void
        _M_set_length_and_sharable(size_type l);

        /// 获取当前字符串对象第一个字符的指针.
        CharT*
        _M_refdata();

        /**
         *  为当前字符串对象增加一个引用,即将当前字符串引用计数加1,然后返
         *  回第一个字符的地址.
         *  当字符串是空串(并且 FULLY_DYNMIC_STRING==0),只是返回第一个字符
         *  的地址,而不会增加引用.
         */
        CharT*
        _M_refcopy();

        /**
         *  新建一个字符串对象,容量为 capacity,并且是 sharable 的.
         *  @param old_capacity 用来优化,具体参考 libstdc++ 实现.
         */
        static _Rep*
        _S_create(size_type capacity,size_type old_capacity,const Alloc &a){
            // 容量为 capacity 的字符串对象所占内存字节数,注意 (capacity+1)
            // 中的"1"是指空字符数.
            size_type size = sizeof(_Rep)+(capacity+1)*sizeof(CharT);
            // NOTE,在 libstdc++ 中,此处对 size,capacity 的取值进行了优化.

            void *place = _Raw_bytes_alloc(a).allocate(size);
            _Rep *r = new (place) _Rep;
            r->_M_capacity = capacity;
            r->_M_set_sharable();
            return r;
        }

        /**
         *  根据当前字符串,克隆一个新的字符串对象,新字符串对象中存放的字符
         *  数组与当前字符串对象中存放的字符数组相同.
         *  @param a 新字符串对象使用的内存分配器.
         *  @param res 新字符串对象.capacity = 当前.length+res;
         */
        CharT*
        _M_clone(const Alloc &a,size_type res=0){
            int new_capacity = _M_length+res;
            _Rep *r = _S_create(new_capacity,_M_capacity,a);
            if(_M_length > 0)
                _M_copy(r->_M_refdata(),_M_refdata(),_M_length);
            r->_M_set_length_and_sharable(_M_length);
            return r->_M_refdata();
        }

        /**
         *  获取一个新的字符串对象,新字符串对象中包含的字符数组与当前
         *  字符串中包含的字符数组一样.若当前字符串对象不可被共享,则
         *  会调用 _M_clone() 克隆一个新字符串对象.若当前字符串可共享,则
         *  直接返回 _M_refcopy().
         *  @param a 新字符串对象使用的内存分配器.
         *  @param b 当前字符串对象使用的内存分配器.
         */
        CharT*
        _M_grab(const Alloc &a,const Alloc &b){
            return !_M_is_leaked() ?
                   _M_refcopy() : _M_clone(a);
        }

        /**
         *  释放当前字符串对象所占的内存,包括 _Rep 结构体以及字符数组
         *  所占的内存.按理说,当字符串是空串(并且 FULLY_DYNMIC_STRING==0)
         *  时,不应该释放(因为此时内存是静态分配).但是在该函数内并没有
         *  检测,即该函数只负责释放内存,所有必要的检测由上层函数
         *  _M_dispose() 负责.
         *  @param a 当前字符串对象的内存分配器.
         */
        void
        _M_destroy(const Alloc &a){
            // 需要回收的内存字节数.
            size_type size = sizeof(_Rep) + (_M_capacity+1)*sizeof(CharT);
            _Raw_bytes_alloc(a).deallocate(this,size);
            return ;
        }

        /**
         *  调用该函数回收当前字符串对象所占的内存空间(在当前字符串对象
         *  被析构时调用).当以下情况时,并不会释放内存:
         *    1. 若当前字符串对象仍被其他字符串对象引用时,并不会释放内存.
         *    2. 当前字符串对象是空串,并且 FULLY_DYNMIC_STRING==0 时,也不会
         *       释放内存
         *  NOTE,此处忽略了原子性,以及线程安全.
         */
        void
        _M_dispose(const Alloc &a){
#if GLIBCXX_FULLY_DYNMIC_STRING == 0
             if(this != &_S_empty_rep())
#endif
             {
                // < 0 或者 ==0,均表明当前字符串对象仅被自己引用着.
                if(_M_refcount <= 0)
                    _M_destroy(a);
                else
                    --_M_refcount;
             }
        }

    }; // struct _Rep

    /**
     *  根据上面分析的字符串对象的结构,可知一个字符串对象需要保存2个数据:
     *    1. CharT* 指针,指向着第一个字符.
     *    2. Alloc 对象,用于分配,释放内存.
     *  那么现在我们有3种方式来实现;
     *    class basic_string{ // 第一种情况,sizeof(basic_string) == 16.
     *      Alloc a;
     *      CharT *data;
     *    };
     *
     *    class basic_string{ // 2;sizeof(basic_string) == 16;
     *      struct _Alloc_hider{
     *          Alloc a;
     *          CharT *data;
     *      };
     *
     *      _Alloc_hider data;
     *    };
     *
     *    class basic_string{ // 3;sizeof(basic_string) == 8.
     *      struct _Alloc_hider:public Alloc{
     *          CharT *data;
     *      };
     *
     *      _Alloc_hider data;
     *    };
     *  So,知道 _Alloc_hider 的意思了吧.
     */
    struct _Alloc_hider: public _Alloc{
        CharT *_M_p;

        _Alloc_hider(CharT *data,const Alloc &a);
    };
private: // 静态;工具函数.

    /// 将自 s 指向的地址开始 n 个字符拷贝到 d 指向的缓冲区中.要求:不重叠
    static void
    _M_copy(CharT *d,const CharT *s,size_type n);

    static void
    _M_move(CharT *d,const CharT *s,size_type n);

    static void
    _M_assign(CharT *d,size_type n,CharT ch);

    /// 将区间 [first,last) 包含的字符拷贝到 d 指向的缓冲区中.
    template<class Iterator>
    static void
    _S_copy_chars(CharT *d,Iterator first,Iterator last);

    static void
    _S_copy_chars(CharT* p, iterator k1, iterator k2);

    static void
    _S_copy_chars(CharT* p, const_iterator k1, const_iterator k2);

    static void
    _S_copy_chars(CharT* p, CharT* k1, CharT* k2);

    static void
    _S_copy_chars(CharT* p, const CharT* k1, const CharT* k2);

    /**
     *  比较 n1 与 n2 的值;返回正值,表明 n1>n2;返回负值,表明 n1<n2;返回
     *  0 表明 n1==n2.
     */
    static int
    _S_compare(size_type n1,size_type n2);


    /**
     *  对下面 _S_construct*() 函数的说明.
     *  只有最后三个 _S_construct() 来是干实事的函数,前 4 个 construct() 只是入口
     *  这 4 个 construct() 会根据情况来调用最下面的 3 个 construct.
     *  对前 4 中 construct() 进行一个统一的说明,见下:
     *              _S_construct(Iter first,Iter last,const Alloc&);
     *                  Iter 是/                         \ Iter 不是整型
     *                   整型 /                           \ 是真正的迭代器
     *       _S_construct_aux(,,,__true_type)     _S_construct_aux(,,,__false_type)
     *               |                                  根据迭代器|的特性
     *       _S_construct_aux_2(,,);           _S_construct(,,,input_iterator_tag)/
     *               |                         _S_construct(,,,forwad_iterator_tag)
     *       _S_construct(size_type,CharT,);
     *  1. 如果 Iter 是整型,则 first 是指字符数,而 last 是指字符.此时就是构建具有
     *     first 个 last 字符的字符串.
     *  2. 否则构建一个字符串,其初始值由区间 [first,last) 填充.
     *      unsigned long long num = 7;
     *      unsigned long long ch = 'c';
     *      std::string test("helloworld");
     *      // 7 个 'c'
     *      puts(std::string::_S_construct(num,ch,test.get_allocator()));
     *      puts(std::string::_S_construct(test.begin(),test.end(),
     *           test.get_allocator()));
     */

    template<typename Iter>
    static CharT*
    _S_construct_aux(Iter first,Iter last,const Alloc &a,__false_type);

    template<typename IntType>
    static CharT*
    _S_construct_aux(IntType first,IntType last,const Alloc &a,__true_type);

    static CharT*
    _S_construct_aux_2(size_type n,CharT ch,const Alloc &a);

    template<typename Iter>
    static CharT*
    _S_construct(Iter first,Iter last,const Alloc &a);

    /**
     *  创建一个新的字符串对象,初始值由区间 [first,last) 填充,然后返回第一个字符
     *  的地址.要求迭代器类型 Iter 是 input_iterator_tag 类型.
     */
    template<typename Iter>
    static CharT*
    _S_construct(Iter first,Iter last,const Alloc &a,input_iterator_tag);

    /**
     *  创建一个新的字符串对象,初始值由区间 [first,last) 填充,然后返回第一个字符
     *  的地址.要求迭代器类型 Iter 是 forward_iterator_tag 类型.
     */
    template<typename Iter>
    static CharT*
    _S_construct(Iter first,Iter last,const Alloc &a,forward_iterator_tag){
        if(first == last)
            return _Rep::_S_empty_rep()._M_refdata();
        size_type size = std::distance(first,last);
        _Rep *r = _Rep::_S_create(size,0,a);
        _S_copy_chars(r->_M_refdata(),first,last);
        r->_M_set_length_and_sharable(size);
        return r->_M_refdata();
    }

    /// 创建一个新的字符串对象,初始值为 n 个 ch 字符;然后返回第一个字符的地址.
    static CharT*
    _S_construct(size_type n,CharT ch,const Alloc &a){
        if( n==0 ) // 空串,此时不需要分配空间,而是直接返回已经存在的空串.
            return _Rep::_S_empty_rep()._M_refdata();
        _Rep *r = _S_create(n,0,a);
        _M_assign(r->_M_refdata(),n,ch);
        r->_M_set_length_and_sharable(n);
        return r->_M_refdata();
    }


private: // 非静态;数据成员
    mutable _Alloc_hider _M_dataplus;

private: // 非静态;函数成员;

    /// 获取当前字符串对象的第一个字符的地址.
    CharT*
    _M_data() const{
        return _M_dataplus._M_p;
    }

    CharT*
    _M_data(CharT *ptr){
        return _M_dataplus._M_p = ptr;
    }

    /// 获取当前字符串对象中包含的 _Rep 对象的地址.
    _Rep*
    _M_rep() const{
        return (_Rep*)_M_data()-1;
    }

    /**
     *  获取当前字符串对象的 begin,end 迭代器;此时 [begin,end) 区间就是
     *  当前字符串的全部字符.
     *  与 begin(),end() 的区别就是 ibegin(),iend() 没有调用 _M_leak().
     */
    iterator
    _M_ibegin() const{
        return _M_dataplus._M_p;
    }

    iterator
    _M_iend() const{
        return _M_dataplus._M_p+size();
    }

    /**
     *  当需要用长度为 len2 的区间替换 [pos,pos+len1) 范围时,我们应该做什
     *  么,以一种简单的情况考虑,此时
     *    1. 我们应该创建一个新的字符串对象
     *    2. 然后将原字符串 [0,pos) 范围内的内容拷贝到新字符串 [0,pos) 处
     *    3. 然后在新字符串中空出长度为 len2 的空间,即 [pos,pos+len2) 留空.
     *    4. 然后再将原字符串 [pos+len1,size) 内的内容拷贝到新字符串
     *       [pos+len2,) 范围内.如下图:
     *   原字符串:
     *     0       pos pos+len1    size
     *     +--------+-----+---------+
     *     +--------+-----+---------+
     *   新字符串,丢弃了原字符串 [pos,pos+len1) 范围内的内容:
     *     +---------+---------+-----------------+
     *     | [0,pos) |   len2  | [pos+len1,size) |
     *     +---------+---------+-----------------+
     *  _M_mutate() 就是用于实现上述功能,并且其只在必要的时候才创建新的字符
     *  串:
     *   1. len2 过大,导致新字符串的 length 大于原字符串的 capacity.或者
     *   2. 当前字符串存在多个引用.
     *  其他情况下,_M_mutate() 在原址进行操作.
     *  @param pos,len1 pos 是指原字符串中的下标,[pos,pos+len1) 是合法区间
     *                  即整个 [pos,pos+len1) 都位于当前字符串中.
     *  @param len1,len2 单位都是字符个数;而不是字节.
     */
    void
    _M_mutate(size_type pos,size_type len1,size_type len2){
        size_type old_size = size();
        size_type new_size = old_size+len2-len1;  // 新字符串的长度.
        // 见上"原字符串"图,how_much 就是在区间 [pos,pos+len1) 右侧未修改的区域.
        size_type how_much = old_size-(pos+len1);
        if(new_size > capacity() || _M_rep()->_M_is_shared()){
            // 此时需要分配新的字符串.
            _Rep *r = _Rep::_S_create(new_size,capacity(),get_allocator());
            if(pos > 0)
                _M_copy(r->_M_refdata(),_M_data(),pos);
            if(how_much > 0)
                _M_copy(r->_M_refdata()+pos+len2,_M_data()+pos+len1,how_much);
            _M_rep()->_M_dispose(get_allocator());
            _M_data(r->_M_refdata());
        }else if(how_much>0 && len2!=len1){
            // 在原址进行操作,则 [0,pos) 范围内的内容就不需要拷贝了,此时只
            // 需要移动 [pos+len1,size) 范围内的内容.当 how_much 为 0 或者
            // len2==len1 时,此时都没有必要移动.
            _M_move(_M_data()+pos+len2,_M_data()+pos+len1,how_much);
        }
        _M_rep()->_M_set_length_and_sharable(new_size);
        return ;
    }

    /**
     *  首先确保当前字符串对象,仅被其自身引用(即 refcount==0,若 refcount>0
     *  则执行一个 detach() 操作).然后将其设置为不可共享的.
     *  若当前字符串是空串,并且引用自 _S_empty_rep_storage,则直接返回.
     */
    void
    _M_leak_hard(){
#if GLIBCXX_FULLY_DYNMIC_STRING == 0
        if(_M_rep() != &_Rep::_S_empty_rep())
#endif
        {
            if(_M_rep()->_M_is_shared())
                _M_mutate(0,0,0); // 类似 detach() 操作.
            _M_rep()->_M_set_leaked();
        }
    }

    /**
     *  当当前字符串对象是可共享的时,首先将确保当前字符串对象仅被其自身
     *  引用,然后将其设置为不可共享.
     */
    void
    _M_leak(){
        if(!_M_rep()->_M_is_leaked())
            _M_leak_hard();
    }

    /**
     *  检测 pos 是否合法,若不合法,则抛出异常;否则返回 pos.
     *  pos 的合法范围应该是 [0,size()];注意 size() 也是合法范围,此时指向
     *  着空字符.
     *  @param s 字符串;用作异常说明.
     */
    size_type
    _M_check(size_type pos,const char *s) const;

    /**
     *  检测 n1,n2 的合法性;若不合法,则抛出异常.
     *  n1,n2 的合法要求 size()+n2-n1 <= max_size();
     *  @param s 字符串;用作异常说明.
     */
    void
    _M_check_length(size_type n1,size_type n2,const char *s) const;

    /**
     *  pos 是当前字符串的一处下标,其合法范围是 [0,size()];off 是长度,
     *  即自 pos 开始,长度为 off.该函数会检测 off 的合法性,当 off 过大时
     *  就会返回 off 的最大值( size()-pos );否则直接返回 off.
     */
    size_type
    _M_limit(size_type pos,size_type off) const{
        size_type off_max = size()-pos;
        return off>off_max ? off_max : off;
    }

    /**
     *  检测 s 存放的地址是否与当前字符串重叠,返回真,则表明不重叠
     *  当 s 位于 [_M_data(),_M_data()+size()] 时,就会认为是重叠的
     */
    bool
    _M_disjunct(const CharT *s) const{
        return s < _M_data() || _M_data()+size() < s;
    }

    /**
     *  使用区间 [s,s+n2) 范围内的字符来替换当前字符串中 [pos1,pos1+n1) 区间.
     *  _M_replace_safe() 并不能处理重叠的情况.该函数对参数的要求:
     *    1. [pos1,pos1+n1) 位于字符串中.
     *    2. [pos1,pos1+n1) 与 [s,s+n2) 不能重叠
     */
    basic_string&
    _M_replace_safe(size_type pos1,size_type n1,const CharT *s,size_type n2){
        _M_mutate(pos1,n1,n2);
        if(n2 > 0)
            _M_copy(_M_data()+pos1,s,n2);
        return *this;
    }

protected:

public: // 函数成员,静态数据成员.
    static const size_type npos = (size_type)(-1);

    /// 获取当前字符串实现中,字符串最多能容纳的字符个数.
    size_type
    max_size() const{
        return _Rep::_S_max_size;
    }

    /**
     *  获取当前字符串所能容纳的最大字符个数.
     *  注意与 max_size() 的区别,max_size() 是返回当前字符串实现中,字符串最多能
     *  容纳的字符个数.
     */
    size_type
    capacity() const{
        return _M_rep()->_M_capacity;
    }

    /// 获取当前字符串使用的内存分配器对象.
    allocator_type
    get_allocator() const{
        return _M_dataplus;
    };

    /// 获取当前字符串中存放的字符个数.
    size_type
    size() const{
        return _M_rep()->_M_length;
    }

    /// 将区间 [s,s+n) 赋值给当前字符串.[s,s+n) 可以是当前字符串的子串.
    basic_string&
    assign(const CharT *s,size_type n){
        // 赋值,其实也就是一个替换的行为,即将整个字符串替换为 [s,s+n);所以此时
        // 在检测整个字符串与 [s,s+n) 不会重叠之后,就直接调用 _M_replace_safe().
        //   * 当 s 不位于整个字符串内时,此时不会重叠,
        //   * 当 s 位于整个字符串内,但是当前字符串存在多个引用,此时会创建一个
        //     新的字符串,而且新字符串与 [s,s+n) 一定不会重叠,所以也可以放心调用.
        if(_M_disjunct(s) || _M_rep()->_M_is_shared())
           return _M_replace_safe(0,size(),s,n);
        else{
            // 此时 [s,s+n) 是当前字符串的子串,进行原址操作.
            size_type pos = s-_M_data();
            if( pos>0 ){ // 若 pos==0,则没必要执行任何复制.
                // 此时就是将 [s,s+n) 范围内的内容移/复制到 _M_data() 处.
                // 即可以直接调用 _M_move(_M_data(),s,n);
                if(pos>=n)  // LD.此时调用 _M_copy() 也是安全的,并且效率更高.
                    _M_copy(_M_data,s,n);
                else
                    _M_move(_M_data,s,n);
            }
            _M_rep()->_M_set_length_and_sharable(n);
            return *this;
        }
    }

    /// 确保当前字符串仅被其自身引用,而且至少可以存放 res 个字符.
    void
    reserve(size_type res){
        if(res > capacity() || _M_rep()->_M_is_shared()){
             // 此时需要分配新的内存.
             char *tmp = _M_rep()->_M_clone(get_allocator(),res-size());
             _M_rep()->_M_dispose(get_allocator());
             _M_data(tmp);
        }
        return ;
    }

    /// 在当前字符串对象中追加 n 个 ch 字符.
    basic_string&
    append(size_type n,CharT ch){
        if( n==0 )
            return *this;
        size_type new_size = n+size();
        reserve(new_size);
        _M_assign(_M_data()+size(),n,ch);
        _M_rep()->_M_set_length_and_sharable(new_size);
        return *this;
    }

    /**
     * 移除当前字符串中 [pos,pos+n) 区间内容,当 n 过大时,移除从 pos 起(包括pos)
     * 一直到字符串结尾的所有内容.
     */
    basic_string&
    erase(size_type pos,size_type n=npos){
        if( n > size()-pos )
            n = size()-pos;
        _M_mutate(pos,n,0);
        return *this;
    }

    /**
     * 将当前字符串的长度设置为 new_size,若 new_size > 当前字符串的长度,则新增
     * 部分使用 ch 进行初始化.
     */
    void
    resize(size_type new_size,CharT ch=CharT()){
        if(new_size > size())
            append(new_size-size(),ch);
        else if(new_size < size())
            erase(new_size);
        return ;
    }

    /**
     * 将区间 [buf,buf+n) 追加到当前字符串的末尾.
     * libstdcxx 中考虑到了 [buf,buf+n) 可能是当前字符串的子串,我可没有想到这个.
     */
    basic_string&
    append(const CharT *buf,size_type n){
        if( n==0 )
            return *this;

        size_type new_size = size()+n;
        if(new_size > capacity() || _M_rep()->_M_is_shared()){
            if(_M_disjunct(buf)) // [buf,buf+n) 不是当前字符串的子串.
                reserve(new_size);
            else{
                // [buf,buf+n) 是当前字符串的子串,此时直接 reserve() 可能会释放当前
                // 字符串所占的内存,即区间 [buf,buf+n) 可能会失效,
                size_type off = buf-_M_data();
                reserve(new_size);
                buf = _M_data()+off;
            }
        }

        _M_copy(_M_data()+size,buf,n);
        _M_rep()->_M_set_length_and_sharable(new_size);
        return *this;
    }
};

}; // namespace std

#endif // org_wxw_stl_study_include_bits_basic_string_h_
